use std::env;
use clap::Parser;
use clap::Subcommand;

use crate::command::BuilderType;
use crate::database::Database;
use crate::database::DbType;
use crate::history::History;

const DEFAULT_FORMAT_STR: &str = "123qwe!@#";

#[derive(Parser)]
#[command(version, author, about, long_about = None)]
#[command(propagate_version = true)]
pub struct PassKey {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Create a password
    Create {
        /// Appoint app's name
        app: String,
        /// Appoint a pattern
        #[arg(short, long)]
        pattern: Option<String>,
        /// Save the password with a message
        #[arg(short, long, value_name = "MESSAGE")]
        save: Option<String>,
        /// Use old password generator
        #[arg(long)]
        old: bool,
    },
    /// Delete passwords
    Delete {
        ids: Vec<String>,
    },
    /// List passwords
    List {
        /// Query by app name
        app: Option<String>,

        #[arg(long)]
        show_id: bool,

        #[arg(long)]
        show_pattern: bool,
    },
}

impl PassKey {
    pub fn run(&self) {
        let db = DbType::Sqlite.get();
        match &self.command {
            Commands::Create { app, pattern, save, old } => {
                Self::create(app, pattern, save, old, &db);
            }
            Commands::Delete { ids } => {
                for id in ids {
                    Self::delete(id, &db);
                }
            }
            Commands::List{ app, show_id, show_pattern} => {
                let historys = Self::query(app, &db);
                History::print_historys(&historys, *show_id, *show_pattern);
            }
        }
    }

    fn query(app: &Option<String>, db: &Box<dyn Database>) -> Vec<History> {
        if let Some(query) = app {
            db.query(&query)
        } else {
            db.query_all()
        }
    }

    fn delete(id: &str, db: &Box<dyn Database>) {
        db.remove(&id);
    }

    fn create(app: &str,
        pattern: &Option<String>,
        save: &Option<String>,
        old: &bool,
        db: &Box<dyn Database>) 
    {
        let pattern = match pattern.clone() {
            Some(v) => v,
            None => env::var("PASSKEY_PATTERN")
                .map_or(DEFAULT_FORMAT_STR.into(), |x| x),
        };

        // 获取密码生成器
        let mut builder = BuilderType::SimpleV2.get_builder();
        if *old {
            builder = BuilderType::SimpleV1.get_builder();
        }

        let password = builder.build(&pattern, &app);
        // 打印密码
        println!("{} -> {}", app, password);

        // 保存密码
        if let Some(msg) = save {
            let his = History::new(&app, &pattern, &password, &msg);
            db.save(&his);
        }
    }
}

